package cxm.proj.xtalk.smack;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.packet.Presence;

import cxm.lib.util.MyLog;

public class User {
	private enum UserState {
		Logout,
		Loginning,
		Login,
		Logouting
	}

	private String username;
	private String password;
	private Connector connector;
	private UserState userState = UserState.Logout;
	
	public User(String username, String password) {
		this.username = username;
		this.password = password;
		this.connector = ConnectManager.getInstance().getConnector();
	}
	
	// async login, callback execute on ui thread
	public void login(ConnectTaskResultHandle taskResultHandle,
			Object taskResultHandleTag) throws UserException {
		MyLog.Log(MyLog.Level.Debug, "Login with current state " + this.userState);
		if (this.isLogin()) {
			MyLog.Log(MyLog.Level.Error, "Already login");
			throw new UserException(
					"Current state not logout: " + this.userState);
		}
		
		this.connector.handleAsyncTask(new ConnectTaskHandle() {
			@Override
			public int taskHandle(Connector connector) {
				if (login())
					return 0;
				else
					return -1;
			}
		}, taskResultHandle, taskResultHandleTag);
		this.userState = UserState.Loginning;
		MyLog.Log(MyLog.Level.Debug, "Setting current state " + this.userState);
	}
	
	// sync login
	public boolean login() {
		if (UserState.Login == this.userState) {
			MyLog.Log(MyLog.Level.Error, "Already login\n");
			return false;
		}
		
		Connector connector = ConnectManager.getInstance().getConnector();
		try {
			// check connection first
			if (!connector.isConnected())
				connector.connect();
			
			// login
			connector.getConnection().login(username, password);
			MyLog.Log(MyLog.Level.Debug, "Login success for user: " + username);
			// sleep a while for login success
			try {
				Thread.sleep(300, 0);
			} catch (Exception e) {
				MyLog.Log(MyLog.Level.Error, "Sleep failed: " + e);
			}
			Presence presence = new Presence(Presence.Type.available);
			connector.getConnection().sendPacket(presence);
			// sleep a while for send packet success
			try {
				Thread.sleep(300, 0);
			} catch (Exception e) {
				MyLog.Log(MyLog.Level.Error, "Sleep failed: " + e);
			}
			userState = UserState.Login;
			return true;
		} catch (Exception e) {
			MyLog.Log(MyLog.Level.Error, String.format(
					"Cannot login user %s: %s" , username, e.toString()));
			userState = UserState.Logout;
			return false;
		}
	}
	
	public void logout(ConnectTaskResultHandle taskResultHandle,
			Object taskResultHandleTag) throws UserException {
		MyLog.Log(MyLog.Level.Debug, "Logout with current state " + this.userState);
		if (UserState.Login != this.userState)
			throw new UserException(
					"Current state not login: " + this.userState);
		
		this.connector.handleAsyncTask(new ConnectTaskHandle() {
			@Override
			public int taskHandle(Connector connector) {
				try {
					// send unavailable package
					Presence presence = new Presence(Presence.Type.unavailable,
							"", 1, Presence.Mode.away);
					connector.getConnection().sendPacket(presence);
					// sleep a while for send packet success
					Thread.sleep(300, 0);
				} catch (Exception e) {
					MyLog.Log(MyLog.Level.Error, "Sleep failed: " + e);
				}
				// disconnect
				try {
					connector.disconnect();
				} catch (Exception e) {
					MyLog.Log(MyLog.Level.Error, "Cannot disconnect: " + e);
				}
				// sleep a while for send packet success
				try {
					Thread.sleep(300, 0);
				} catch (Exception e) {
					MyLog.Log(MyLog.Level.Error, "Sleep failed: " + e);
				}
				userState = UserState.Logout;
				return 0;
			}
		}, taskResultHandle, taskResultHandleTag);
		// mark state
		this.userState = UserState.Logouting;
	}
	
	// check user state login or loginning
	public boolean isLogin() {
		return UserState.Login == this.userState ||
				UserState.Loginning == this.userState;
	}
	
	// check user state logined
	public boolean isLogined() {
		return UserState.Login == this.userState;
	}
	
	public boolean isLogout() {
		return UserState.Logout == this.userState ||
				UserState.Logouting == this.userState;
	}
	
	public String getName() {
		return this.username + "@" + ConnectManager.getInstance().getServiceName();
	}

	public Chat createChat(String name, MessageListener listener) {
		return this.connector.getConnection().getChatManager().createChat(
				name + "@" + ConnectManager.getInstance().getServiceName(), listener);
	}

	public Chat createNewChat(String name, MessageListener listener) {
		return this.connector.getConnection().getChatManager().createChat(
				name, listener);
	}
}
